/*********************************************************************************
 * Software License Agreement (BSD License)
 * Copyright (c) 2012, Carlos D. Correa (info@ngraph.org)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of netzen nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************************/
#include "propertyBag.h"
#include "object.h"
#include <assert.h>
#include <stdexcept>

/*
PROPERTY_UNKNOWN, // 0
PROPERTY_BOOL,    // 1 bool
PROPERTY_INT,     // 2 int
PROPERTY_FLOAT,   // 3 float
PROPERTY_SIGNED,  // 4 signed
PROPERTY_VEC2,            // 5
PROPERTY_VEC3,            // 6
PROPERTY_STRING,					// 7 string
PROPERTY_ORDINAL,				// 8 also a string
PROPERTY_SELECTION,       // 9
PROPERTY_MULTISELECTION   // 10
 */	

string PropertyBag::format(int type, PropertyBag *bag, string name) {
	if(type<0 || type>=NUM_TYPES) {
		throw std::runtime_error("Incorrect data type");
	}
	assert(parsers);
	assert(parsers[type]);
	return parsers[type]->format(bag, name);
}
void PropertyBag::parse(int type, PropertyBag *bag, string name, string value) {
	if(type<0 || type>=NUM_TYPES) {
		throw std::runtime_error("Incorrect data type");
	}
	assert(bag);
	assert(parsers[type]);
	parsers[type]->parse(bag, name, value);
}

class IntParser:public PropertyParser {
public:
	virtual void parse(string s, void* pvalue) {
		int *value = (int*) pvalue;
		*value = atoi(s.c_str());
	}
	virtual void parse(PropertyBag *bag, string name, string svalue) {
		assert(bag);
		int value = atoi(svalue.c_str());
		bag->setPropertyInt(name, value);
	}
	virtual string format(PropertyBag *bag, string name) {
		int value = bag->getPropertyInt(name);
		char str[200];
    sprintf(str, "%d", value);
    return string(str); 
	}
};

class FloatParser:public PropertyParser {
public:
	virtual void parse(string s, void* pvalue) {
		float *value = (float*) pvalue;
		*value = atof(s.c_str());
	}
	virtual void parse(PropertyBag *bag, string name, string svalue) {
		float value = atof(svalue.c_str());
		bag->setPropertyFloat(name, value);
	}
	virtual string format(PropertyBag *bag, string name) {
		float value = bag->getPropertyFloat(name);
		char str[200];
    sprintf(str, "%g", value);
    return string(str); 
	}
};

class BoolParser:public PropertyParser {
public:
	virtual void parse(string s, void* pvalue) {
		bool *value = (bool*) pvalue;
		*value = (s=="true");
	}
	virtual void parse(PropertyBag *bag, string name, string svalue) {
		bool value = svalue=="true";
		bag->setPropertyBool(name, value);
	}
	virtual string format(PropertyBag *bag, string name) {
		bool value = bag->getPropertyBool(name);
    return string(value? "true":"false");
	}
};

class StringParser:public PropertyParser {
public:
	StringParser() {
	}
	virtual void parse(string s, void* pvalue) {
		string *value = (string*) pvalue;
		*value = s;
	}
	virtual void parse(PropertyBag *bag, string name, string svalue) {
		bag->setPropertyString(name, svalue);
	}
	virtual string format(PropertyBag *bag, string name) {
		string value = bag->getPropertyString(name);
		return value;
	}
};

// TODO
class Vec2Parser:public PropertyParser {
public:
	virtual void parse(string s, void* pvalue) {
		string *value = (string*) pvalue;
		*value = s;
	}
	virtual void parse(PropertyBag *bag, string name, string svalue) {
		bag->setPropertyString(name, svalue);
	}
	virtual string format(PropertyBag *bag, string name) {
		string value = bag->getPropertyString(name);
		return value;
	}
};
class Vec3Parser:public PropertyParser {
public:
	virtual void parse(string s, void* pvalue) {
		string *value = (string*) pvalue;
		*value = s;
	}
	virtual void parse(PropertyBag *bag, string name, string svalue) {
		bag->setPropertyString(name, svalue);
	}
	virtual string format(PropertyBag *bag, string name) {
		string value = bag->getPropertyString(name);
		return value;
	}
};

PropertyParser *PropertyBag::parsers[NUM_TYPES] = { 
	new StringParser(),
	new BoolParser(),
	new IntParser(),
	new FloatParser(),
	new FloatParser(),
	new Vec2Parser(),
	new Vec3Parser(),
	new StringParser(),
	new StringParser(),
	new StringParser(),
	new StringParser()
};


PropertyBag::PropertyBag(const char *type, const char *name): Object(type, name) {
}

PropertyBag::~PropertyBag() {
}

vector<string> PropertyBag::getProperties() {
  vector<string> vec;
  for(map<string,int>::const_iterator it = types.begin(); it !=types.end(); ++it) {
    vec.push_back((it->first));
  }
  return vec;
}
bool PropertyBag::hasProperty(string name) {
  return (types.find(name)!=types.end());
}

